package com.ht.config.log.aspect;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.sql.SqlUtils;
import com.ht.abnormal.HtException;
import com.ht.config.log.annotation.SysLog;
import com.ht.config.log.event.SysLogEvent;
import com.ht.constant.BusConstant;
import com.ht.constant.DicConstants;
import com.ht.module.sys.entity.SysOperLog;
import com.ht.util.IPUtils;
import com.ht.util.UserUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.SqlSessionFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.CodeSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 * @ProjectName: ht-end
 * @ClassName: OperLogAspect
 * @Author: hejialun
 * @Description: 切面日志
 * @Date: 2022/4/26 15：58：02
 */
@Aspect
@Component
@Slf4j
public class OperLogAspect {
    @Resource
    private HttpServletRequest httpServletRequest;
    @Resource
    private HttpServletResponse httpServletResponse;
    @Resource
    private ApplicationContext applicationContext;


    @Around("@annotation(sysLog)")
    public Object around(ProceedingJoinPoint point, SysLog sysLog) throws IllegalAccessException {
        SysOperLog log=new SysOperLog();
        //获取模块标题
        RequestMapping requestMapping = point.getTarget().getClass().getAnnotation(RequestMapping.class);
        if (StrUtil.isEmpty(sysLog.title())) {
            //如果标题等于空则设置RequestMapping的第一个值为标题
            log.setTitle(requestMapping.value()[0]);
        } else {
            log.setTitle(sysLog.title());
        }

        //获取当前请求对象
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        //设置请求方式类型-GET/POST/DELETE/PUT
        log.setRequestMethod(request.getMethod());
        //设置请求参数
        try {
            log.setParam(JSON.toJSONString(getParam(point)));
        } catch (Exception e) {
            e.printStackTrace();
        }
        //设置请求URL
        log.setOperUrl(request.getRequestURI());
        //设置请求方法名
        log.setMethodName(point.getTarget().getClass().getName());
        //获取操作说明
        log.setMsg(sysLog.msg());
        //获取操作类型
        log.setOperType(sysLog.type());
        //设置ip
        log.setOperIp(IPUtils.getIpAddr(httpServletRequest));
        //设置操作用户
        log.setUserId(UserUtil.getUserId());
        //设置操作时间时间
        log.setOperTime(LocalDateTime.now());
        //设置操作状态
        Object o = null;
        try {
            log.setStates(DicConstants.OperLogStates.NORMAL);
            o = point.proceed();
        } catch (Throwable throwable) {
            //异常处理
            log.setStates(DicConstants.OperLogStates.ERROR);
            log.setErrMsg(throwable.getMessage());
            throwable.printStackTrace();
            throw new HtException(throwable.getMessage());
        }finally {
            applicationContext.publishEvent(new SysLogEvent(log));
            //在Request中设置请求参数
            httpServletResponse.setHeader(BusConstant.LOG_KEY,log.getId());

        }
        return o;
    }



    /**
     * @Author hejialun
     * @Date 14:56 2022/4/28
     * @Description TODO(获取切面接口字段)
     * @param point
     * @return java.util.Map<java.lang.String,java.lang.Object>
     */
    public static Map<String, Object> getParam(ProceedingJoinPoint point) {
        //定义字段参数map
        Map<String,Object> map=new HashMap<>();
        Object[] values = point.getArgs();
        String[] names = ((CodeSignature) point.getSignature()).getParameterNames();
        for (int i = 0; i < names.length; i++) {
            map.put(names[i],values[i]);
        }
        return map;
    }

    /**
     * @Author hejialun
     * @Date 15:17 2022/4/28
     * @Description TODO(获取 DML 的 方式（insert、delete、update、select）)
     * @param sql
     * @return java.lang.String
     */
    public static String getSqlDML(String sql) {

        if(StrUtil.isEmpty(sql)){
            return null;
        }
        try {
            sql=sql.trim();
            int endIndex = sql.indexOf(" ")!=-1?sql.indexOf(" "):sql.length()>=6?6:sql.length();
            return sql.substring(0, endIndex).toUpperCase();
        } catch (Exception e) {
            log.error("SqlUtils- 获取sql的DML 异常",e);
            return null;
        }
    }

}